/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package rnavigator.view;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Arc2D;
import java.util.ArrayList;
import java.util.LinkedList;
import javax.swing.JPanel;
import rnavigator.model.Base;
import rnavigator.model.Coord2D;
import rnavigator.model.Knot;
import rnavigator.model.Structure;

/**
 *
 * @author Elias la Cour
 */
public class StructurePanel extends JPanel {

    private boolean debug = false;
    private Structure structure = null;
    private int xCenter, yCenter;
    double radius;
    Coord2D center;

    @Override
    protected void paintComponent(Graphics g) {
        //nødvendigt her med super call?
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g;
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        xCenter = getWidth() / 2;
        yCenter = getHeight() / 2;
        if (structure != null) {
            g2d.drawString("C", xCenter, yCenter);
            System.out.println("Structure no longer null in structurepanel");

            //for testing circlebycenter()
//                Point2D testp1 = new Point2D.Double((xCenter-100),(yCenter-50));
//                Point2D testp2 = new Point2D.Double((xCenter-100),(yCenter+50));
//                Point2D testp3 = new Point2D.Double((xCenter+50),(yCenter+100));
//                Point2D testp4 = new Point2D.Double((xCenter-50),(yCenter+100));
//                Point2D testp5 = new Point2D.Double((xCenter-50),(yCenter-100));
//                Point2D testp6 = new Point2D.Double((xCenter+50),(yCenter-100));
//                Point2D testCC = new Point2D.Double((xCenter),(yCenter));
//                g2d.setColor(Color.GREEN);
//                g2d.drawString("CC", xCenter, yCenter);

//                getComplementaryCenter(testp1, testp2, testCC, g2d);
//                g2d.setColor(Color.red);
//                Arc2D arc2 = new Arc2D.Double();
//                arc2.setArcByCenter(xCenter, yCenter, 100, -45, 78, Arc2D.OPEN);
            drawCircularFeynman(g2d);
        }
    }
//evt returner graphicsklassen?

    public void drawCircularFeynman(Graphics2D g2d) {
        LinkedList<Knot> knots;
        ArrayList<Base> bases;
        double theta, h;
        int x, y, count, distance;
        double angle, length, cosAngle;
        Coord2D p1, p2;
        float xf, yf;
        Arc2D arc;

        bases = structure.getBases();
        knots = structure.getKnots();
        center = new Coord2D(xCenter, yCenter);
        if (debug) {
            System.out.println("calcCircularFeynman called");
        }
        count = bases.size();
        theta = (2 * Math.PI) / count;
        radius = Math.min(getWidth() / 3, getHeight() / 3);
        h = radius * Math.cos(theta / 2);
        int startX = (int) (xCenter - (Math.sin(theta / 2) * radius));



        //loop to plot x y coords for bases
        for (Base b : bases) {
            g2d.setColor(Color.BLACK);
            theta = ((2 * Math.PI * b.getPosition()) / count);
            x = (int) Math.round(xCenter + radius * Math.cos(theta));
            y = (int) Math.round(yCenter + radius * Math.sin(theta));
            b.setX(x);
            b.setY(y);
        }
        //loop to draw bases
        for (Base b : bases) {
            g2d.setColor(Color.BLACK);
            g2d.drawString(b.getNucleotide() + "", b.getX(), b.getY());
        }
        //loop to draw knots
        for (Knot k : knots) {
            Base b = bases.get(k.getPos1());
            Base b2 = bases.get(k.getPos2());
            distance = (int) getDistance(b.getX(), b.getY(), b2.getX(), b2.getY());
            /**
             * Cos(B) = (a^2 + c^2 - b^2) / (2 * a * c)
             */
            cosAngle = (double) ((radius * radius) + (distance * distance) - (radius * radius)) / (2 * distance * radius);
            angle = Math.toDegrees(cosAngle);
            //System.out.println(cosAngle + " cosangle & angle " + angle);
            //angle = ((32.0*32.0) + (37.0*37.0) - (25.0*25.0)) / (2.0 * 32.0 * 37.0);
            /**
            draw(double x,
            double y,
            double w,
            double h,
            double angSt,
            double angExt,
            int closure)
             */
            if (b.isKnot()) {
                g2d.setColor(Color.BLUE);
                //g2d.drawLine(b.getX(), b.getY(), b2.getX(), b2.getY());
                arc = new Arc2D.Float();
                p1 = b.getCoord2D();
                p2 = b2.getCoord2D();
                Arc2D newArc = getComplementaryCenter(p1, p2, center, g2d);
                g2d.draw(newArc);
                //g2d.drawArc(b.getX(), b.getY(), distance, distance, 0, 90);
                //g2d.draw(new Arc2D.Double(b.getX(), b.getY(), distance, distance, 0, 180, Arc2D.OPEN));
                //g2d.draw(new Arc2D.Double(b.getX(), b.getY(), distance, distance, angle, 180, Arc2D.OPEN));
            }
            if (b.isPseudoKnot()) {
                g2d.setColor(Color.RED);
                //g2d.drawLine(b.getX(), b.getY(), b2.getX(), b2.getY());
                arc = new Arc2D.Float();
                p1 = b.getCoord2D();
                p2 = b2.getCoord2D();
                Arc2D newArc = getComplementaryCenter(p1, p2, center, g2d);
                g2d.draw(newArc);
                //float xMid = (b.getX()+b2.getX())/2;
                //float yMid = (b.getY()+b2.getY())/2;
                //p2=new Point2D.Float(xMid, yMid);
                //double arcRad = (getDistance(p1, p2) / 2);
                //System.out.println("arcrad disT:" + arcRad);
                //arc.setArcByTangent(p1, p3, p2, (float) arcRad);
                //g2d.draw(arc);
                
                //g2d.drawLine((int) p1.getX(), (int) p1.getY(), (int) p2.getX(), (int) p2.getY());
                
                //testing arcsByCenter to work
                g2d.setColor(Color.green);
                Arc2D arc2 = new Arc2D.Float();
                arc2.setArcByCenter(xCenter, yCenter, 100, 90, 90, Arc2D.OPEN);
                g2d.draw(arc2);
                //Point2D offsetCenter = calcOffsetCenter(p1, p2, p3);
//                g2d.drawString("C", (float) offsetCenter.getX(), (float) offsetCenter.getY());




                if (debug) {
                    System.out.println("p1:" + p1.getX() + "," + p1.getY() + " p2:" + p2.getX() + "," + p2.getY() + " center:" + center.getX() + "," + center.getY());
                }
                //g2d.draw(arc);
                //g2d.drawArc(b.getX(), b.getY(), 100, 100, 0, 180);
            }
        }

//        g2d.setColor(Color.red);
//            Point2D p1 = new Point2D.Float(xMidf-100, yMidf);
//            Point2D p2 = new Point2D.Float(xMidf+100, yMidf);
//            Point2D p3 = new Point2D.Float(xMidf, yMidf+100);
//            //g2d.drawLine((int)p1.getX(), (int)p1.getY(), (int)p2.getX(), (int)p2.getY());
//            Arc2D arc = new Arc2D.Float(0f,0f,0f,0f,0f,0f,0);
//            arc.setArcByTangent(p1, p2, p3, 50);
//            g2d.draw(arc);
    }
  

    public double getDistance(int ix, int iy, int ix2, int iy2) {
        /**
         * |AB| = squareroot((x2-x1)^2 + (y2-y1)^2)
         */
        double x = ix;
        double y = iy;
        double x2 = ix2;
        double y2 = iy2;
        double distance = Math.sqrt(((x2 - x) * (x2 - x)) + ((y2 - y) * (y2 - y)));
        return distance;
    }

    public double getDistance(double x1, double y1, double x2, double y2) {
        /**
         * |AB| = squareroot((x2-x1)^2 + (y2-y1)^2)
         */
        double distance = Math.sqrt(((x2 - x1) * (x2 - x1)) + ((y2 - y1) * (y2 - y1)));
        return distance;
    }

    public double getDistance(Coord2D p1, Coord2D p2) {
        /**
         * |AB| = squareroot((x2-x1)^2 + (y2-y1)^2)
         */
        double x = p1.getX();
        double y = p1.getY();
        double x2 = p2.getX();
        double y2 = p2.getY();
        double distance = Math.sqrt(((x2 - x) * (x2 - x)) + ((y2 - y) * (y2 - y)));
        return distance;
    }

    /**
     * @param debug the debug to set
     */
    public void setDebug(boolean debug) {
        this.debug = debug;
    }

    /**
     * @param structure the structure to set
     */
    public void setStructure(Structure structure) {
        System.out.println("new structure set in Structurepanel()");
        this.structure = structure;
        repaint();
    }

    public Arc2D getComplementaryCenter(Coord2D p1, Coord2D p2, Coord2D center, Graphics2D g2d) {
        double p1x = p1.getX();
        double p1y = p1.getY();
        double p2x = p2.getX();
        double p2y = p2.getY();
        //cx & cy coords of the original circle
        double cx = center.getX();
        double cy = center.getY();
        //ccx & ccy coords of the complementary circle
        double ccx, ccy;
        //ccxstart & ccystart 0 degrees point for the complementary circle
        double ccxStart, ccyStart;
        double arcRadius, tmpRadius;

        //Slope form:  m = (y2-y1)/(x2-x1)
        double m1 = (p1y - cy) / (p1x - cx);
        double m2 = (p2y - cy) / (p2x - cx);

        // Slope of tangent form: mt = -1 / m
        // if slope = 0 (vertical line) choose a high number (almost vertical)
        // to avoid NaN error
        if (m1 == 0) {
            m1 = 9999;
        } else {
            m1 = -1 / m1;
        }
        if (m2 == 0) {
            m2 = 9999;
        } else {
            m2 = -1 / m2;
        }
        /*
         * to isolate y-intercept (b) of the line:
         * Slope intercept form: y = m * x + b  == 
         * b = y - (m*x) 
         */

        double b1 = p1y - (m1 * p1x);
        double b2 = p2y - (m2 * p2x);

        /*
         * The X coord of the complementary circle (px) is found when setting 
         * the y-coordinate of tangent 1 to the y-coordinate of tangent 2:
         * tangent1 = tangent2 ==
         * m1*x1+b1 = m2 * x2 * b2 ==
         * px = (b2 - b1) / (m1 - m2)
         * 
         * and then inserting x into the intercept-slope form to find y:
         * py = (m * x) +b
         */
        ccx = (b2 - b1) / (m1 - m2);
        ccy = (m1 * ccx) + b1;

        // Pythagoras to find complementary circle radius
        arcRadius = getDistance(p1.getX(), p1.getY(), ccx, ccy);
        //double arcRadius = Math.sqrt(((ccx - p1x) * (ccx - p1x)) + ((ccy - p1y) * (ccy - p1y)));
        //System.out.println("arcRadius" + arcRadius);

        double sideB = getDistance(cx, cy, ccx, ccy);

        //======== Cosinus relation. Her brugt til at beregne vinklen A //sweep vinklen
        // A = cos^-1((b*b+c*c-a*a)/)2*b*c))

        tmpRadius = getDistance(p1, center);
        double sweep = ((sideB * sideB) + (arcRadius * arcRadius)
                - (tmpRadius * tmpRadius))
                / (2 * sideB * arcRadius);

        sweep = Math.toDegrees(Math.acos(sweep))*2;

        // Calculate starting angle  =========================================================
        //Starting point for the complementary circle
        ccxStart = ccx + arcRadius;
        ccyStart = ccy;
        if (debug) {
            g2d.drawString("P1", (int) p1x, (int) p1y);
            g2d.drawString("P2", (int) p2x, (int) p2y);
            g2d.drawString("Comp", (int) ccx, (int) ccy);
        }
        /*
         * temp beregninger:
         * find vinkel C (fra startpunkt til sweep begynder)
         * først skal modsatstående katete (c) findes (pythagoras)
         * 
         */

        double sideModsatStartvinkel = Math.sqrt(((ccxStart - p1x) * (ccxStart - p1x)) + ((ccyStart - p1y) * (ccyStart - p1y)));
        double distancep1psx = getDistance(ccxStart, ccyStart, p1x, p1y);
        double distancep2psx = getDistance(ccxStart, ccyStart, p2x, p2y);
        double oppositeSide = sideModsatStartvinkel;

        //======== Cosinus relation. Her brugt til at beregne vinklen A 
        //
        // A = cos^-1((b*b+c*c-a*a)/)2*b*c))

        double startAngle = ((arcRadius * arcRadius) + (arcRadius * arcRadius)
                - (oppositeSide * oppositeSide))
                / (2 * arcRadius * arcRadius);
        //System.out.println("startangle" + startAngle);


//        if (startAngle < -1) {
//            startAngle = -1;
//        }
        //startAngle=Math.abs(startAngle);
        startAngle = Math.acos(startAngle);
        //System.out.println("startangle radians" + startAngle);
        startAngle = Math.toDegrees(startAngle);
        //System.out.println("StartAngle" + startAngle);

        //der må være en smartere måde at tegne buerne på?

        if (p1y > ccy) {
            startAngle = (360 - (startAngle));
        }
        if (p2y > ccy && p1y < ccy) {
            sweep = sweep;
        }
        //if(p2y)
        //startAngle = 360 - startAngle;
        //System.out.println("StartAngle" + startAngle);



        //======== Test om punkt1's y-værdi er mindre end centrums y-værdi.
// I så fald skal den beregnede vindes sættes til minus

//
//        if (p1x < cx) {
//            startAngle = -(startAngle);
//        }
        Arc2D arc = new Arc2D.Double();
        arc.setArcByCenter(ccx, ccy, arcRadius, startAngle, sweep, Arc2D.OPEN);

        g2d.draw(arc);


        return arc;
    }
}
